package test
{
import flexunit.framework.TestCase;
import flexunit.framework.TestSuite;

import com.fit4as.fit.ActionFixture;
import com.fit4as.fit.Fixture;
import com.fit4as.fit.Parse;
import com.fit4as.fit.ScientificDouble;
import com.fit4as.fit.Summary;
import com.fit4as.fit.TypeAdapter;

import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.system.System;

import eg.ArithmeticFixture;
import eg.ArithmeticColumnFixture;
import eg.Calculator;
import eg.music.Browser;
import eg.music.Display;
import eg.music.Realtime;
import eg.music.MusicLibrary;

import com.fit4as.util.io.StringWriter;
import com.fit4as.util.reflect.ClassUtil;


    // Copyright (c) 2002 Cunningham & Cunningham, Inc.
    // Released under the terms of the GNU General Public License version 2 or later.

public class FrameworkTest extends TestCase {

    public function FrameworkTest(name : String) {
        super(name);
    }

    public static function suite():TestSuite {
        var ts:TestSuite = new TestSuite();
        ts.addTest(new FrameworkTest("testTypeAdapter"));
        ts.addTest(new FrameworkTest("testScientificDouble"));
        ts.addTest(new FrameworkTest("testEscape"));
        ts.addTest(new FrameworkTest("testRunExamples"));

        return ts;
    }

    private function isCloseTo(x : Number, y : Number, epsilon : Number = 0.00001) : Boolean
    {
        return Math.abs(x - y) < epsilon;
    }

    public function testTypeAdapter() : void {
        var f : TestFixture = new TestFixture();
        var fClass : Class = ClassUtil.getClass( f );

        var a : TypeAdapter = TypeAdapter.onField( f, ClassUtil.getField( fClass, "sampleInt"));
        a.set(a.parse("123456"));
        assertEquals(1, 123456, f.sampleInt);
        assertEquals(2, "-234567", a.parse("-234567").toString());

        a = TypeAdapter.onField(f, ClassUtil.getField(fClass, "sampleInteger"));
        a.set(a.parse("54321"));
        assertEquals(3, "54321", f.sampleInteger.toString());

        a = TypeAdapter.onMethod(f, ClassUtil.getMethod(fClass, "pi", new Array()));
        assertTrue(4, isCloseTo(3.14159, Number(a.invoke())));
        assertTrue(5, isCloseTo(3.14159862, Number(a.invoke())));

        a = TypeAdapter.onField(f, ClassUtil.getField(fClass, "name"));
        a.set(a.parse("xyzzy"));
        assertEquals(7, "xyzzy", f.name);

        a = TypeAdapter.onField(f, ClassUtil.getField(fClass, "sampleFloat"));
        a.set(a.parse("6.02e23"));
        assertTrue(8, isCloseTo(6.02e23, f.sampleFloat, 1e17));

        /*
        a = TypeAdapter.onField(f, ClassUtil.getField( fClass, "sampleArray"));
        a.set(a.parse("1,2,3"));
        assertEquals(9, 1, f.sampleArray[0]);
        assertEquals(10, 2, f.sampleArray[1]);
        assertEquals(11, 3, f.sampleArray[2]);
        assertEquals(12, "1, 2, 3", a.toString(f.sampleArray));
        assertTrue(13, a.equals([1,2,3], f.sampleArray));
        */
        /*
        a = TypeAdapter.onField(f, ClassUtil.getField( fClass, "sampleDate"));
        var date : Date = new Date(1949, 4, 26);
        a.set(a.parse(DateFormat.getDateInstance().format(date)));
        assertEquals(date, f.sampleDate);
        */
        a = TypeAdapter.onField(f, ClassUtil.getField(fClass, "sampleByte"));
        a.set(a.parse("123"));
        assertEquals(14, 123, f.sampleByte);

        a = TypeAdapter.onField(f, ClassUtil.getField(fClass, "sampleShort"));
        a.set(a.parse("12345"));
        assertEquals(15, 12345, f.sampleShort);
    }

    public function testScientificDouble() : void {
        var pi : Number = 3.141592865;
        //equals is not called automatically in AS3, therfore these tests fail
        //assertEquals(ScientificDouble.valueOf("3.14"), pi);
        //assertEquals(ScientificDouble.valueOf("3.142"), pi);
        //assertEquals(ScientificDouble.valueOf("3.1416"), pi);
        //assertEquals(ScientificDouble.valueOf("3.14159"), pi);
        //assertEquals(ScientificDouble.valueOf("3.141592865"), pi);
        assertTrue(!ScientificDouble.valueOf("3.140").equals(pi));
        assertTrue(!ScientificDouble.valueOf("3.144").equals(pi));
        assertTrue(!ScientificDouble.valueOf("3.1414").equals(pi));
        assertTrue(!ScientificDouble.valueOf("3.141592863").equals(pi));
        //equals is not called automatically in AS3, therfore these tests fail
        //assertEquals(ScientificDouble.valueOf("6.02e23"), 6.02e23);
        //assertEquals(ScientificDouble.valueOf("6.02E23"), 6.024E23);
        //assertEquals(ScientificDouble.valueOf("6.02e23"), 6.016e23);
        assertTrue(!ScientificDouble.valueOf("6.02e23").equals(6.026e23));
        assertTrue(!ScientificDouble.valueOf("6.02e23").equals(6.014e23));
    }

    public function testEscape() : void {
        var junk : String = "!@#$%^*()_-+={}|[]\\:\";',./?`";
        assertEquals(junk, Fixture.escape(junk));
        assertEquals("", Fixture.escape(""));
        assertEquals("&lt;", Fixture.escape("<"));
        assertEquals("&lt;&lt;", Fixture.escape("<<"));
        assertEquals("x&lt;", Fixture.escape("x<"));
        assertEquals("&amp;", Fixture.escape("&"));
        assertEquals("&lt;&amp;&lt;", Fixture.escape("<&<"));
        assertEquals("&amp;&lt;&amp;", Fixture.escape("&<&"));
        assertEquals("a &lt; b &amp;&amp; c &lt; d", Fixture.escape("a < b && c < d"));
        assertEquals("a<br />b", Fixture.escape("a\nb"));
    }

    public function testRunExamples() : void {
        //reference fixtures to include them into build
        var arithmeticFixtures : Array = [ArithmeticFixture, ArithmeticColumnFixture, Summary];
        //runExample("arithmetic", 37, 10, 0, 2);

        var calculatorExampleFixtures : Array = [ Calculator, Summary ];
        //runExample("CalculatorExample", 75, 9, 0, 0);

        var musicExampleFixtures : Array = [ActionFixture, Browser, MusicLibrary, Summary]; //, RowFixture, Browser, Display, Realtime, Summary ];
        //runExample("MusicExample", 95, 0, 0, 0);
    }

    protected function runExample(file : String, right : int, wrong : int, ignores : int, exceptions : int) : void
    {
        var url : String = "examples/" + file + ".html";
        var loader : URLLoader = new URLLoader();
        loader.dataFormat = URLLoaderDataFormat.TEXT;
        var request : URLRequest = new URLRequest(url);
        loader.addEventListener(Event.COMPLETE, addAsync(handleLoaderComplete, 1000, arguments));
        loader.load(request);
    }

    protected function handleLoaderComplete(evt : Event, args : Array) : void
    {
        var input : String = String(URLLoader(evt.target).data);
        var fixture : Fixture = new Fixture();
        var tables : Parse;

        if (input.indexOf("<wiki>") >= 0) {
            tables = Parse.createParse(input, ["wiki", "table", "tr", "td"]);
            fixture.doTables(tables.parts);
        } else {
            tables = Parse.createParse( input, ["table", "tr", "td"]);
            fixture.doTables(tables);
        }

        var output : StringWriter = new StringWriter();
        tables.print(output);
        output.close();

        System.setClipboard(output.getContent());

        var file : String = args[ 0 ];
        var right : int = args[ 1 ];
        var wrong : int = args[ 2 ];
        var ignores : int = args[ 3 ];
        var exceptions : int = args[ 4 ];

        assertEquals(file + " right", right, fixture.counts.right);
        assertEquals(file + " wrong", wrong, fixture.counts.wrong);
        assertEquals(file + " ignores", ignores, fixture.counts.ignores);
        assertEquals(file + " exceptions", exceptions, fixture.counts.exceptions);
    }


}
}

